#! /usr/bin/python3
# -*- coding: UTF-8 -*-
"""
  作者: 小肥爬爬
  简书: https://www.jianshu.com/u/db796a501972
  gitee: https://gitee.com/xiaofeipapa/python-toolkit
  您可以自由转载此博客文章, 恳请保留原链接, 谢谢!

  将fabric api 再封装一层, 使之更好用
"""
from fabric import Connection
import os, os.path
from invoke import Responder


class FabException(Exception):
    def __init__(self, msg):
        Exception.__init__(self, msg)


# 运行远程命令
def run(conn, cmd, hide=True, warn=True):

    r = conn.run(cmd, encoding='utf8', hide=hide, warn=warn)

    result, err = r.stdout.strip(), r.stderr.strip()
    if err:
        raise FabException(err)

    return result


# 检查文件夹是否存在
def is_dir_exists(conn, dir_path):
    cmd = '[ -d ' + dir_path + ' ] && echo ok'
    _stdin, _stdout, _stderr = conn.client.exec_command(cmd)
    result = _stdout.read().strip().decode('utf8')

    return result == 'ok'


# 检查文件文件是否存在
def is_file_exists(conn, file_path):
    cmd = '[ -f ' + file_path + ' ] && echo ok'
    _stdin, _stdout, _stderr = conn.client.exec_command(cmd)
    result = _stdout.read().strip().decode('utf8')

    return result == 'ok'


# 判断是否有该文件夹, 不存在时可以通过参数控制生成文件夹
def check_has_dir(conn, dir_path, create_if_not_exist=True):

    if not is_dir_exists(conn, dir_path):
        if create_if_not_exist:
            run(conn, 'mkdir -p ' + dir_path)


# 判断是否有该文件, 不存在时可以通过参数控制生成文件夹
def check_has_file(conn, file_path, create_if_not_exist=True):

    if not is_dir_exists(conn, file_path):
        if create_if_not_exist:
            run(conn, 'touch ' + file_path)


# 在服务器安全删除文件/文件夹的方法
def safe_rm(conn, file_path):

    # 先检查是否存在
    try:
        run(conn, 'ls ' + file_path)
    except FabException:
        print(file_path + ' 不存在')
        return

    # 在/tmp下生成当天目录
    result = run(conn, 'date +%Y-%m-%d')

    trash_dir = '/tmp/my_trash/' + result
    check_has_dir(conn, trash_dir)

    # 在当天下生成uuid, 确保mv 不会失败
    result = run(conn, 'uuidgen')
    trash_dir = trash_dir + '/' + result
    check_has_dir(conn, trash_dir)

    run(conn, 'mv ' + file_path + ' ' + trash_dir)


# 追加一行到文件末尾
def append_line(conn, file_path, content):
    if not is_file_exists(conn, file_path):
        return

    cmd = "echo '" + content + "' >> " + file_path
    run(conn, cmd)


# 关闭连接
def close_connection(conn):
    conn.run('exit')
    conn.close()


# 检查是否需要下载
def check_download(conn, file_path, file_md5, down_link):

    file_name = os.path.basename(file_path)

    if is_file_exists(conn, file_path):
        run_result = conn.run('md5sum ' + file_path, encoding='utf8', hide=False, warn=True)
        # print(run_result.stdout)
        md5 = run_result.stdout.split(' ')[0].strip()
        if md5 == file_md5:
            print('---- ' + file_name + ' 已经存在,不需要下载\n')
            return

        else:
            # "删除"之, 重新下载
            run(conn, 'mv -f ' + file_path + ' /tmp')

    # 下载
    print('---- 正在下载 ' + file_name + ' ......\n')
    # run(conn, down_link, hide=False, warn=True)

    wget(conn, down_link)

    print('---- 下载 ' + file_name + ' 已完成\n')


def wget(conn, download_link):
    # wget 会将正常输出放到 stderr, 所以要用这个方法来判断是否有错误输出
    cmd = 'wget ' + download_link + ' 2>&1 | grep -i "failed\|error"'
    r = conn.run(cmd, encoding='utf8', hide=False, warn=True)
    stdout, err = r.stdout.strip(), r.stderr.strip()

    # print('---- 下载结果: #### ' + result)
    # print('---- 下载err? ##### ' + err)

    if stdout:
        raise FabException(stdout)


def ubuntu_passwd(conn, username, pwd):

    resp1 = Responder(
        pattern=r'Enter new UNIX password:',
        response=pwd + '\n'
    )

    resp2 = Responder(
        pattern=r'Retype new UNIX password:',
        response=pwd + '\n'
    )

    conn.run('passwd ' + username, pty=True, hide=True, watchers=[resp1, resp2])


def ubuntu_adduser(conn, username, pwd):

    resp1 = Responder(
        pattern=r'Enter new UNIX password:',
        response=pwd + '\n'
    )

    resp2 = Responder(
        pattern=r'Retype new UNIX password:',
        response=pwd + '\n'
    )

    resp3 = Responder(
        pattern=r'Full Name \[\]:',
        response='\n'
    )

    resp4 = Responder(
        pattern=r'Room Number \[\]:',
        response='\n'
    )

    resp5 = Responder(
        pattern=r'Work Phone \[\]:',
        response='\n'
    )

    resp6 = Responder(
        pattern=r'Home Phone \[\]:',
        response='\n'
    )

    resp7 = Responder(
        pattern=r'Other \[\]:',
        response='\n'
    )

    resp8 = Responder(
        pattern=r'Is the information correct\? \[Y/n\]',
        response='Y\n'
    )

    conn.run('adduser ' + username, pty=True, hide=True, watchers=[resp1, resp2, resp3, resp4, resp5, resp6,
                                                                   resp7, resp8])

